package com.hrp.book.base

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.ViewModelProvider
import me.yokeyword.fragmentation.SupportFragment
import java.lang.reflect.GenericSignatureFormatError
import java.lang.reflect.MalformedParameterizedTypeException
import java.lang.reflect.ParameterizedType

abstract class BaseFragment<DB : ViewDataBinding, VM : BaseViewModel> : SupportFragment() {

    protected lateinit var binding: DB

    lateinit var viewModel: VM

    protected lateinit var baseActivity: BaseActivity<*, *>

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = DataBindingUtil.inflate(inflater, getLayoutId(), container, false)
        if (hasViewModel()) {
            viewModel = createViewModel()
        }
        val activity = _mActivity
        if (activity is BaseActivity<*, *>) {
            baseActivity = activity
        }
        return binding.root
    }

    override fun onLazyInitView(savedInstanceState: Bundle?) {
        super.onLazyInitView(savedInstanceState)
        if (hasViewModel()) {
            viewModel.initialize()
        }
    }

    @Suppress("UNCHECKED_CAST")
    protected open fun getViewModelClass(): Class<VM> {
        var temp: Class<*>? = javaClass
        var z: Class<*>? = null
        while (z == null && null != temp) {
            z = getInstancedGenericKClass(temp)
            temp = temp.superclass
        }
        // 泛型擦除会导致z为null
        return (z ?: BaseViewModel::javaClass) as Class<VM>
    }

    protected open fun createViewModel(): VM {
        return ViewModelProvider(this).get(getViewModelClass())
    }


    @LayoutRes
    abstract fun getLayoutId(): Int


    open fun hasViewModel(): Boolean {
        return true
    }


    /**
     * get generic parameter VM
     *
     * @param z
     * @return
     */
    private fun getInstancedGenericKClass(z: Class<*>): Class<*>? {
        try {
            val type = z.genericSuperclass
            if (type is ParameterizedType) {
                val types = type.actualTypeArguments
                for (temp in types) {
                    if (temp is Class<*>) {
                        if (BaseViewModel::class.java.isAssignableFrom(temp)) {
                            return temp
                        }
                    } else if (temp is ParameterizedType) {
                        val rawType = temp.rawType
                        if (rawType is Class<*> && BaseViewModel::class.java.isAssignableFrom(
                                rawType
                            )
                        ) {
                            return rawType
                        }
                    }
                }
            }
        } catch (e: GenericSignatureFormatError) {
            e.printStackTrace()
        } catch (e: TypeNotPresentException) {
            e.printStackTrace()
        } catch (e: MalformedParameterizedTypeException) {
            e.printStackTrace()
        }
        return null
    }

    override fun onBackPressedSupport(): Boolean {
        return true
    }

}